/*************************************************************************
 *************************************************************************
 	 	 	 	 	 	 	 M2SMA : Agent.cpp
 *************************************************************************
 *
 	 Copyright (C) 2008
 	 Steven Costiou, Julien Yven; Master 2 Complex Systems
 	 University of Western Brittany (UBO), Brest, France
 *
 *************************************************************************
 *************************************************************************
 *
 	 Copyright (C) 2011
 	 M2SMA reworked and simplified core, Steven Costiou, France
 *
 **************************************************************************
 **************************************************************************
 *
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/
 *
 **************************************************************************
 **************************************************************************/

#include "Agent.h"
#include "Engine.h"

Agent::Agent()
{
	/**
	 * An agent shall be constructed with an system engine as parent engine.
	 * An agent cannot exists outside an agent-system.
	 */
	throw new missingEngineAtAgentCreationException();
}

Agent::Agent(Engine* anEngine)
{
	if(anEngine == NULL)
		throw new missingEngineAtAgentCreationException();

	this->fullClassNameHierarchy = new vector<string>();
	this->addClassName("Agent");
	this->fullClassName = getFullClassName();
	this->parentEngine = anEngine;
}

Agent::~Agent()
{
	delete fullClassNameHierarchy;
}

/** WARNING ***
 * An agent created through a copy constructor from an other agent in a given system is automatically
 * added to the same system. Thus, it is not needed to add it to this system manually.
 * A new name is automatically built for this copied agent, because an agent's name is unique.
 * If this copied agent can be added to an other system engine, it belongs to its originator's system as well;
 * a copied agent can then be present in multiple systems, but with a unique pointer (this is why engine's clean-up
 * shall be done with extreme precaution).
 */
Agent::Agent(const Agent& anAgent, Engine* anEngine) /// FIXME Paramètre enEngine à récupérer via le getParentEngine()
{
	selfCopyFrom(anAgent, anEngine);
	this->parentEngine->createAgent(this); /// TODO : est-ce de la responsabilité de l'agent de faire ça ?
}

void Agent::selfCopyFrom(const Agent& anAgent, Engine* anEngine)
{
	this->name = anAgent.name;
	this->fullClassNameHierarchy = new vector<string>();

	unsigned int fullClassNameCopySize = anAgent.fullClassNameHierarchy->size();
	for(unsigned int i = 0; i < fullClassNameCopySize; ++i)
		this->fullClassNameHierarchy->push_back(anAgent.fullClassNameHierarchy->at(i));

	this->parentEngine = anAgent.parentEngine;
}

Agent& Agent::operator=(const Agent& anAgent)
{
	if (this != &anAgent)
	{
		if(fullClassNameHierarchy != NULL)
			delete fullClassNameHierarchy;

		selfCopyFrom(anAgent, anAgent.parentEngine);
	}
	return *this;
}

bool operator==(const Agent& anAgent, const Agent& anOtherAgent)
{
	return anAgent.isEqualTo(anOtherAgent);
}

bool operator!=(const Agent& anAgent, const Agent& anOtherAgent)
{
	return !(anAgent == anOtherAgent);
}

ostream& operator<<(ostream& os, const Agent& anAgent)
{
	os << anAgent.fullClassNameHierarchy->at(anAgent.fullClassNameHierarchy->size() - 1) << " : " << anAgent.name;
	return os;
}

void Agent::display()
{
}

bool Agent::isEqualTo(const Agent& anAgent) const
{
	return  ((this->name == anAgent.name) &&
			(this->fullClassName == anAgent.fullClassName) &&
			(this->parentEngine == anAgent.parentEngine));
}

string Agent::getFullClassName()
{
	stringstream agentFullClassName;
	vector<string>::iterator it;

	for (it = this->fullClassNameHierarchy->begin(); it != this->fullClassNameHierarchy->end(); it++)
		agentFullClassName << *it;

	return agentFullClassName.str().c_str();
}

void Agent::addClassName(string cName)
{
	this->fullClassNameHierarchy->push_back(cName);
}

void Agent::live()
{
	cout << "This is generic agent : " << this->name << endl;
}

void Agent::stopSystem()
{
	this->parentEngine->stopSystem();
};
